#include "address.h"
#include <sstream>
#include <netdb.h>
#include <ifaddrs.h>
#include <stddef.h>

#include "endian.h"


//static sylar::Logger::ptr g_logger = SYLAR_LOG_NAME("system");

template<class T>
static T CreateMask(uint32_t bits) { //创建一个几位的掩码
    return (1 << (sizeof(T) * 8 - bits)) - 1; //返回子网掩码的十进制数
}

//统计十进制数值中1的数量
template<class T>
static uint32_t CountBytes(T value) {
    uint32_t result = 0;
    for(; value; ++result) {
        value &= value - 1;
    }
    return result;
}

//返回任意的Address地址
Address::ptr Address::LookupAny(const std::string& host,
                                int family, int type, int protocol) {
    std::vector<Address::ptr> result;
    if(Lookup(result, host, family, type, protocol)) {
        return result[0];
    }
    return nullptr;
}

//返回任意的IPAddress地址
IPAddress::ptr Address::LookupAnyIPAddress(const std::string& host,
                                int family, int type, int protocol) {
    std::vector<Address::ptr> result;
    if(Lookup(result, host, family, type, protocol)) {
        //for(auto& i : result) {
        //    std::cout << i->toString() << std::endl;
        //}
        for(auto& i : result) {
            IPAddress::ptr v = std::dynamic_pointer_cast<IPAddress>(i); //把地址转换为IPAddress
            if(v) { //找到就返回
                return v;
            }
        }
    }
    return nullptr;
}

//通过字符串获取地址
bool Address::Lookup(std::vector<Address::ptr>& result, const std::string& host,
                     int family, int type, int protocol) {
    addrinfo hints, *results, *next; //用作getaddrinfo函数的参数
    hints.ai_flags = 0; 
    hints.ai_family = family; //指定地址族
    hints.ai_socktype = type; //指定协议类型
    hints.ai_protocol = protocol; //指定协议类型
    hints.ai_addrlen = 0;
    hints.ai_canonname = NULL;
    hints.ai_addr = NULL;
    hints.ai_next = NULL;

    std::string node; //主机名
    const char* service = NULL; //存储端口号

    //检查 ipv6address serivce
    if(!host.empty() && host[0] == '[') {
        const char* endipv6 = (const char*)memchr(host.c_str() + 1, ']', host.size() - 1); //查找到]这个符号，并且返回该位置的指针
        if(endipv6) {
            //TODO check out of range
            if(*(endipv6 + 1) == ':') { //判断下一个是否是 :
                service = endipv6 + 2; //把端口号提取出来
            }
            //endipv6 - host.c_str() 计算从 host 字符串开始到 endipv6 指针之间的字符数
            node = host.substr(1, endipv6 - host.c_str() - 1); //提取主机号 赋值给node
        }
    }

    //检查 node serivce
    if(node.empty()) { //如果node为空
        service = (const char*)memchr(host.c_str(), ':', host.size()); //查找 : ，查找到把后面的端口号存放到service
        if(service) { //如果service不为空
            if(!memchr(service + 1, ':', host.c_str() + host.size() - service - 1)) { //host.c_str() + host.size() - service 计算从端口号开始到字符串末尾的字符数
                //如果没有找到
                node = host.substr(0, service - host.c_str()); //
                ++service; //把指针加1，表示指向冒号变成指向端口号的第一个
            }
        }
    }

    if(node.empty()) { //如果还是为空 表明没有端口号
        node = host; // 把主机号直接给到node
    }
    int error = getaddrinfo(node.c_str(), service, &hints, &results); //调用函数解析host
    if(error) {
        std::cout << "Address::Lookup getaddress(" << host << ", "
            << family << ", " << type << ") err=" << error << " errstr="
            << gai_strerror(error) << std::endl;
        return false;
    }

    next = results; //这里是一个结构体
    while(next) {
        //ai_addr：指向 sockaddr 结构的指针，包含了实际的套接字地址信息。
        //ai_next：指向下一个 addrinfo 结构的指针，形成了一个链表，用于存储多个地址信息。
        result.push_back(Create(next->ai_addr, (socklen_t)next->ai_addrlen));
        //SYLAR_LOG_INFO(g_logger) << ((sockaddr_in*)next->ai_addr)->sin_addr.s_addr;
        next = next->ai_next;
    }

    freeaddrinfo(results);
    return !result.empty();
}

//通过本机网卡 获取本机ip地址
bool Address::GetInterfaceAddresses(std::multimap<std::string
                    ,std::pair<Address::ptr, uint32_t> >& result,
                    int family) {
    struct ifaddrs *next, *results; //声明两个指向 ifaddrs 结构体的指针，next 用于遍历，results 用于接收 getifaddrs 函数的结果。
    if(getifaddrs(&results) != 0) { //获取本地网络接口的地址信息
        std::cout << "Address::GetInterfaceAddresses getifaddrs "
            " err=" << errno << " errstr=" << strerror(errno) << std::endl;
        return false;
    }

    try {
        for(next = results; next; next = next->ifa_next) {
            Address::ptr addr;
            uint32_t prefix_len = ~0u;
            //检查 family 参数是否与接口地址族匹配，如果不匹配则跳过当前接口
            if(family != AF_UNSPEC && family != next->ifa_addr->sa_family) {
                continue;
            }
            switch(next->ifa_addr->sa_family) {
                case AF_INET:
                    {
                        addr = Create(next->ifa_addr, sizeof(sockaddr_in)); 
                        uint32_t netmask = ((sockaddr_in*)next->ifa_netmask)->sin_addr.s_addr; //获取到本机的ip地址信息
                        prefix_len = CountBytes(netmask); //统计1的数量
                    }
                    break;
                case AF_INET6:
                    {
                        addr = Create(next->ifa_addr, sizeof(sockaddr_in6));
                        in6_addr& netmask = ((sockaddr_in6*)next->ifa_netmask)->sin6_addr; //获取到ipv6的结构体
                        prefix_len = 0;
                        for(int i = 0; i < 16; ++i) {
                            prefix_len += CountBytes(netmask.s6_addr[i]); //累加计算1的数量
                        }
                    }
                    break;
                default:
                    break;
            }

            if(addr) {
                result.insert(std::make_pair(next->ifa_name,
                            std::make_pair(addr, prefix_len))); //插入到容器中
            }
        }
    } catch (...) {
        std::cout << "Address::GetInterfaceAddresses exception" << std::endl;
        freeifaddrs(results);
        return false;
    }
    freeifaddrs(results);
    return !result.empty();
}

//获取指定网卡 获取指定的ip地址
bool Address::GetInterfaceAddresses(std::vector<std::pair<Address::ptr, uint32_t> >&result
                    ,const std::string& iface, int family) {
    if(iface.empty() || iface == "*") { //表示用户请求获取所有可用的网络接口地址
        if(family == AF_INET || family == AF_UNSPEC) { //如果是ipv4的地址
            result.push_back(std::make_pair(Address::ptr(new IPv4Address()), 0u)); //0u 表示数值 0，并且是一个无符号整数。
        }
        if(family == AF_INET6 || family == AF_UNSPEC) { //如果是ipv6的地址
            result.push_back(std::make_pair(Address::ptr(new IPv6Address()), 0u));
        }
        return true;
    }

    std::multimap<std::string //一个键可以对应多个值
          ,std::pair<Address::ptr, uint32_t> > results; //创建一个容器

    if(!GetInterfaceAddresses(results, family)) { //获取不到
        return false;
    }

    //its 是一个由两个迭代器组成的对，its.first 指向范围的开始，its.second 指向范围的结束
    auto its = results.equal_range(iface); //使用 results 容器的 
                            //equal_range 方法来获取一个迭代器范围，该范围包含了所有与指定 iface 名称匹配的元素
    for(; its.first != its.second; ++its.first) {
        result.push_back(its.first->second); //在每次迭代中，its.first 指向当前的键值对，
                //its.first->second 是与键关联的值（即 std::pair<Address::ptr, uint32_t>）
    }
    return !result.empty();
}

int Address::getFamily() const {
    return getAddr()->sa_family;
}

std::string Address::toString() const {
    std::stringstream ss;
    insert(ss);
    return ss.str();
}

Address::ptr Address::Create(const sockaddr* addr, socklen_t addrlen) {
    if(addr == nullptr) {
        return nullptr;
    }

    Address::ptr result;
    switch(addr->sa_family) { //不同ip地址需要区分
        case AF_INET: //ipv4
            result.reset(new IPv4Address(*(const sockaddr_in*)addr)); 
            break;
        case AF_INET6: //ipv6
            result.reset(new IPv6Address(*(const sockaddr_in6*)addr));
            break;
        default: //不知道的地址
            result.reset(new UnknownAddress(*addr));
            break;
    }
    return result;
}

bool Address::operator<(const Address& rhs) const {
    socklen_t minlen = std::min(getAddrLen(), rhs.getAddrLen()); //取出最小的长度
    int result = memcmp(getAddr(), rhs.getAddr(), minlen);  //用于比较两个内存块是否相同
    if(result < 0) {
        return true;
    } else if(result > 0) {
        return false;
    } else if(getAddrLen() < rhs.getAddrLen()) {
        return true;
    }
    return false;
}

bool Address::operator==(const Address& rhs) const {
    return getAddrLen() == rhs.getAddrLen()
        && memcmp(getAddr(), rhs.getAddr(), getAddrLen()) == 0;
}

bool Address::operator!=(const Address& rhs) const {
    return !(*this == rhs);
}

//给一个通用的，无论是不是符号ip地址结构的都转一下
IPAddress::ptr IPAddress::Create(const char* address, uint16_t port) {
    addrinfo hints, *results; //声明两个 addrinfo 类型的变量，hints 用于指定 getaddrinfo 函数的搜索条件，
                              //results 用于存储 getaddrinfo 函数返回的结果
    memset(&hints, 0, sizeof(addrinfo));

    hints.ai_flags = AI_NUMERICHOST; //设置 hints 结构体的 ai_flags 成员为 AI_NUMERICHOST，这告诉 getaddrinfo 函数 address 参数是一个数值 IP 地址，而不是一个主机名
    hints.ai_family = AF_UNSPEC; //设置 hints 结构体的 ai_family 成员为 AF_UNSPEC，这使得 getaddrinfo 函数可以返回 IPv4 或 IPv6 地址。

    int error = getaddrinfo(address, NULL, &hints, &results); //调用 getaddrinfo 函数来解析给定的 IP 地址字符串 address。NULL 表示不指定端口号，&results 用于存储解析结果
    if(error) {
        std::cout << "IPAddress::Create(" << address
            << ", " << port << ") error=" << error
            << " errno=" << errno << " errstr=" << strerror(errno) << std::endl;
        return nullptr;
    }

    try {
        IPAddress::ptr result = std::dynamic_pointer_cast<IPAddress>( //强转类型
                Address::Create(results->ai_addr, (socklen_t)results->ai_addrlen));
        if(result) {
            result->setPort(port); //如果转换成功，调用 setPort 方法来设置端口号。
        }
        freeaddrinfo(results); //释放 getaddrinfo 函数分配的内存。
        return result;
    } catch (...) {
        freeaddrinfo(results);
        return nullptr;
    }
}

//将文本型地址转换为需要的地址
IPv4Address::ptr IPv4Address::Create(const char* address, uint16_t port) {
    IPv4Address::ptr rt(new IPv4Address);
    rt->m_addr.sin_port = byteswapOnLittleEndian(port);
    //把字符型的地址转换为对应的ipv4的地址结构，拷贝到结构体中
    int result = inet_pton(AF_INET, address, &rt->m_addr.sin_addr);
    if(result <= 0) {
        std::cout << "IPv4Address::Create(" << address << ", "
                << port << ") rt=" << result << " errno=" << errno
                << " errstr=" << strerror(errno) << std::endl;
        return nullptr;
    }
    return rt;
}

IPv4Address::IPv4Address(const sockaddr_in& address) {
    m_addr = address;
}

IPv4Address::IPv4Address(uint32_t address, uint16_t port) {
    memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sin_family = AF_INET;
    m_addr.sin_port = byteswapOnLittleEndian(port); //转为为网络字节序(大端)
    m_addr.sin_addr.s_addr = byteswapOnLittleEndian(address);
}

sockaddr* IPv4Address::getAddr() {
    return (sockaddr*)&m_addr; //返回sockaddr结构体的地址
}

const sockaddr* IPv4Address::getAddr() const {
    return (sockaddr*)&m_addr; //
}

socklen_t IPv4Address::getAddrLen() const {
    return sizeof(m_addr); //返回结构体大小
}

//插入ip地址
std::ostream& IPv4Address::insert(std::ostream& os) const {
    uint32_t addr = byteswapOnLittleEndian(m_addr.sin_addr.s_addr); //转换为网络字节序
    os << ((addr >> 24) & 0xff) << "." //把int转换为ipv4的形式
       << ((addr >> 16) & 0xff) << "."
       << ((addr >> 8) & 0xff) << "."
       << (addr & 0xff);
    os << ":" << byteswapOnLittleEndian(m_addr.sin_port); //把端口写入
    return os;
}

//广播地址 在局域网（LAN）内发送数据包，以便让所有设备都能接收到
IPAddress::ptr IPv4Address::broadcastAddress(uint32_t prefix_len) {
    if(prefix_len > 32) { //长度大于32位
        return nullptr;
    }

    sockaddr_in baddr(m_addr); //把m_addr值传递给baddr
    baddr.sin_addr.s_addr |= byteswapOnLittleEndian(
            CreateMask<uint32_t>(prefix_len)); //IPv4 地址与子网掩码结合起来，以确定网络地址
    return IPv4Address::ptr(new IPv4Address(baddr)); //返回保存了网络地址的ipv4的智能指针
}

//计算网段
IPAddress::ptr IPv4Address::networdAddress(uint32_t prefix_len) {
    if(prefix_len > 32) {
        return nullptr;
    }

    sockaddr_in baddr(m_addr);
    baddr.sin_addr.s_addr &= byteswapOnLittleEndian(
            CreateMask<uint32_t>(prefix_len));
    return IPv4Address::ptr(new IPv4Address(baddr));
}

//子网掩码
IPAddress::ptr IPv4Address::subnetMask(uint32_t prefix_len) {
    sockaddr_in subnet;
    memset(&subnet, 0, sizeof(subnet));
    subnet.sin_family = AF_INET;
    subnet.sin_addr.s_addr = ~byteswapOnLittleEndian(CreateMask<uint32_t>(prefix_len)); //取反
    return IPv4Address::ptr(new IPv4Address(subnet));
}

uint32_t IPv4Address::getPort() const {
    return byteswapOnLittleEndian(m_addr.sin_port); //获取到端口号
}

//设置端口
void IPv4Address::setPort(uint16_t v) {
    m_addr.sin_port = byteswapOnLittleEndian(v); 
}

IPv6Address::ptr IPv6Address::Create(const char* address, uint16_t port) {
    IPv6Address::ptr rt(new IPv6Address);
    rt->m_addr.sin6_port = byteswapOnLittleEndian(port);
    //把字符型的地址转换为对应的ipv4的地址结构，拷贝到结构体中
    int result = inet_pton(AF_INET6, address, &rt->m_addr.sin6_addr);
    if(result <= 0) {
        std::cout << "IPv6Address::Create(" << address << ", "
                << port << ") rt=" << result << " errno=" << errno
                << " errstr=" << strerror(errno) << std::endl;
        return nullptr;
    }
    return rt;
}

IPv6Address::IPv6Address() {
    memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sin6_family = AF_INET6; //指定地址族
}

IPv6Address::IPv6Address(const sockaddr_in6& address) {
    m_addr = address;
}

IPv6Address::IPv6Address(const uint8_t address[16], uint16_t port) {
    memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sin6_family = AF_INET6;
    m_addr.sin6_port = byteswapOnLittleEndian(port);
    memcpy(&m_addr.sin6_addr.s6_addr, address, 16);
}

sockaddr* IPv6Address::getAddr() {
    return (sockaddr*)&m_addr; 
}

const sockaddr* IPv6Address::getAddr() const {
    return (sockaddr*)&m_addr;
}

socklen_t IPv6Address::getAddrLen() const {
    return sizeof(m_addr);
}

std::ostream& IPv6Address::insert(std::ostream& os) const {
    os << "[";
    uint16_t* addr = (uint16_t*)m_addr.sin6_addr.s6_addr; //把ipv6的地址数组转换为uint16_t指针，方便访问
    bool used_zeros = false; //用来标记是否处理了连续的0值
    //ipv6的格式：2001:0db8:85a3:0000:0000:8a2e:0370:7334
    for(size_t i = 0; i < 8; ++i) { //转换为ipv6的格式
        if(addr[i] == 0 && !used_zeros) { //如果当前的 16 位部分为零，并且之前没有处理过连续的零值，则跳过不输出。
            continue;
        }
        if(i && addr[i - 1] == 0 && !used_zeros) {//如果当前不是第一个部分，且前一个部分为零，并且之前没有处理过连续的零值，
                                                  //则在输出流中插入一个冒号 :，并标记 used_zeros 为 true。
            os << ":";
            used_zeros = true;
        }
        if(i) { //如果不是第一个部分，则在输出流中插入一个冒号 : 作为分隔符。
            os << ":";
        }
        os << std::hex << (int)byteswapOnLittleEndian(addr[i]) << std::dec;//将当前的 16 位部分以十六进制格式输出到流中。
                                                                           //byteswapOnLittleEndian 函数用于在小端系统上将字节序转换为大端，以符合网络字节序。
    }

    if(!used_zeros && addr[7] == 0) {//如果没有处理过连续的零值，并且最后一个部分为零，则在输出流中插入 ::，表示连续的零值
        os << "::";
    }

    os << "]:" << byteswapOnLittleEndian(m_addr.sin6_port); 
    return os;
}

//广播地址
IPAddress::ptr IPv6Address::broadcastAddress(uint32_t prefix_len) {
    sockaddr_in6 baddr(m_addr);
    //这行代码计算了前缀长度 prefix_len 所在的字节索引（除以 8），因为每个字节包含 8 位。
    //CreateMask<uint8_t>(prefix_len % 8) 创建一个掩码，其中前 prefix_len % 8 位为 1，其余位为 0。
    //然后，这个掩码与 baddr.sin6_addr.s6_addr 数组中相应字节的值进行按位或操作，这将翻转该字节中相应的位，从而创建一个“广播”位模式。
    baddr.sin6_addr.s6_addr[prefix_len / 8] |=
        CreateMask<uint8_t>(prefix_len % 8); //
    for(int i = prefix_len / 8 + 1; i < 16; ++i) {
        baddr.sin6_addr.s6_addr[i] = 0xff;//这个 for 循环从 prefix_len / 8 + 1 开始，遍历 sin6_addr.s6_addr 数组的剩余部分，直到数组的末尾
    }                                     //全部置为1
    return IPv6Address::ptr(new IPv6Address(baddr));
}

//网络地址(网段)
IPAddress::ptr IPv6Address::networdAddress(uint32_t prefix_len) {
    sockaddr_in6 baddr(m_addr);
    baddr.sin6_addr.s6_addr[prefix_len / 8] &=
        CreateMask<uint8_t>(prefix_len % 8);
    for(int i = prefix_len / 8 + 1; i < 16; ++i) {
        baddr.sin6_addr.s6_addr[i] = 0x00;
    }
    return IPv6Address::ptr(new IPv6Address(baddr));
}

//子网掩码
IPAddress::ptr IPv6Address::subnetMask(uint32_t prefix_len) {
    sockaddr_in6 subnet;
    memset(&subnet, 0, sizeof(subnet));
    subnet.sin6_family = AF_INET6;
    subnet.sin6_addr.s6_addr[prefix_len /8] =
        ~CreateMask<uint8_t>(prefix_len % 8); //取反

    for(uint32_t i = 0; i < prefix_len / 8; ++i) {
        subnet.sin6_addr.s6_addr[i] = 0xff; //将子网掩码的每个字节设置为 0xff，这表示所有位都是 1
    }
    return IPv6Address::ptr(new IPv6Address(subnet));
}

//获取端口号
uint32_t IPv6Address::getPort() const {
    return byteswapOnLittleEndian(m_addr.sin6_port);
}

//设置端口号
void IPv6Address::setPort(uint16_t v) {
    m_addr.sin6_port = byteswapOnLittleEndian(v);
}

//表示最大的路径长度
static const size_t MAX_PATH_LEN = sizeof(((sockaddr_un*)0)->sun_path) - 1;//类型转换，将 NULL 指针（0）转换为 sockaddr_un 类型的指针

UnixAddress::UnixAddress() {
    memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sun_family = AF_UNIX;
    //offsetof：这是一个宏，用于计算结构体成员相对于结构体起始地址的偏移量。
    m_length = offsetof(sockaddr_un, sun_path) + MAX_PATH_LEN; //偏移量加上长度才是实际长度
}

UnixAddress::UnixAddress(const std::string& path) {
    memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sun_family = AF_UNIX;
    m_length = path.size() + 1;

    if(!path.empty() && path[0] == '\0') {
        --m_length;
    }

    if(m_length > sizeof(m_addr.sun_path)) {
        throw std::logic_error("path too long");
    }
    memcpy(m_addr.sun_path, path.c_str(), m_length);
    m_length += offsetof(sockaddr_un, sun_path);
}

void UnixAddress::setAddrLen(uint32_t v) {
    m_length = v;
}

sockaddr* UnixAddress::getAddr() {
    return (sockaddr*)&m_addr;
}

const sockaddr* UnixAddress::getAddr() const {
    return (sockaddr*)&m_addr;
}

socklen_t UnixAddress::getAddrLen() const {
    return m_length;
}

std::string UnixAddress::getPath() const {
    std::stringstream ss;
    if(m_length > offsetof(sockaddr_un, sun_path)
            && m_addr.sun_path[0] == '\0') {
        ss << "\\0" << std::string(m_addr.sun_path + 1, //表示从sun_path的第一个位置开始
                m_length - offsetof(sockaddr_un, sun_path) - 1); //一直到末尾
    } else {
        ss << m_addr.sun_path;
    }
    return ss.str();
}

std::ostream& UnixAddress::insert(std::ostream& os) const {
    if(m_length > offsetof(sockaddr_un, sun_path)
            && m_addr.sun_path[0] == '\0') {
        return os << "\\0" << std::string(m_addr.sun_path + 1,
                m_length - offsetof(sockaddr_un, sun_path) - 1);
    }
    return os << m_addr.sun_path;
}

//不知道的类型IP
UnknownAddress::UnknownAddress(int family) {
    memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sa_family = family; //给定一个地址族
}

UnknownAddress::UnknownAddress(const sockaddr& addr) {
    m_addr = addr;
}

sockaddr* UnknownAddress::getAddr() {
    return (sockaddr*)&m_addr;
}

const sockaddr* UnknownAddress::getAddr() const {
    return &m_addr;
}

socklen_t UnknownAddress::getAddrLen() const {
    return sizeof(m_addr);
}

std::ostream& UnknownAddress::insert(std::ostream& os) const {
    os << "[UnknownAddress family=" << m_addr.sa_family << "]";
    return os;
}

std::ostream& operator<<(std::ostream& os, const Address& addr) {
    return addr.insert(os);
}

